#!/bin/env -S python '-B'
# -*- coding: utf-8 -*-
BEPINEX_CORE='../BepInEx/core/'
BEPINEX_DLL=['BepInEx.dll','0Harmony.dll']
MOD_ID='Neutron3529.Cheat' # 请修改成你自己喜欢的id，这是mod id的默认值
CSC_COMMAND='csc'
COMPILE_FILE='cheat.cs'
GAME_DLLS=['System.dll','System.Core.dll','UnityEngine.dll','UnityEngine.CoreModule.dll','mscorlib.dll','Assembly-CSharp.dll','Assembly-CSharp-firstpass.dll']

# from os.sys import argv
from subprocess import Popen
from os import remove, listdir
guessing_list=[i for i in os.listdir() if i[-5:].upper()=='_DATA']
guessing_list.sort(key=lambda x:len(x))
try:GAME_NAME=guessing_list[0][:-5]
except:GAME_NAME=''
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('game-name',default='')
parser.add_argument("--bepinex-core", type=string, help="bepinex内核所在位置，请接受这个默认值，而不是更改它", default=BEPINEX_CORE)
parser.add_argument("-i", "--id", type=string, help="本Mod使用的id，请改成你自己的id", default=MOD_ID)
parser.add_argument("-n", "--game-name", type=string, help="游戏名称，用于指向\"../${game-name}_Data\"文件夹，默认由程序自行猜测", default=GAME_NAME)
parser.add_argument("-c", "--csc-command", type=string, help="调用C#编译器csc使用的命令", default=CSC_COMMAND)
parser.add_argument("-f", "--compile-file", type=string, help="程序生成的中间文件，可以不改", default=COMPILE_FILE)
parser.add_argument("-r", "--release", type=bool, action='store-true', help="使用release而不是默认的debug发布")
parser.add_argument("-u", "--extra-using", type=string, action='append', help=f"额外的需要写在using部分的代码，可以反复使用")
parser.add_argument("-d", "--extra-dll", type=string, action='append', help=f"额外的需要引用的dll，可以反复使用以引用多个dll，默认引用dll的位置是../{GAME_NAME}_Data/Managed/")
parser.add_argument("-g", "--git", type=bool, action='store-true', help="顺手上传github")

args = parser.parse_args()

def compiles(extra_dll,MOD_ID=MOD_ID,COMPILE_TO=COMPILE_FILE,git=False):
    dlls=''.join(f'''-r:'../{GAME_NAME}_Data/Managed/{i}' ''' for i in set(GAME_DLLS+extra_dll))
    out=f'''-out:'../BepInEx/plugins/{MOD_ID}.dll' '''
    command=" ".join([CSC_COMMAND+r" -nologo -t:'library"]+dlls+out+f'-optimize {COMPILE_TO}')
    if system(command)==0:
        try:remove(f"../BepInEx/config/{MOD_ID}.cfg")
        except:print(f'删除../BepInEx/config/{MOD_ID}.cfg失败')
        if git: system(f'''git add {FILE_NAME} && git commit -am "`curl -s http://whatthecommit.com/index.txt`"''')

def generate_file(patches,using,MOD_ID=MOD_ID,GAME_NAME=GAME_NAME,release=False):
    FRONT="\n".join(using)+r'''using System;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;

namespace Cheat {
    [BepInPlugin("'''+MOD_ID+r'''", "'''+GAME_NAME+r'''", "0.1.0")]
    public class Cheat : BaseUnityPlugin {'''+('' if release else r'''
        public static Action<string> logger;''')
    defs=''
    PART1=r'''
        void Start() {
            var harmony=new Harmony("Neutron3529.Cheat");'''+('' if release else r'''
            logger=Logger.LogInfo;''')
    ifs=''
    PART2=('' if release else r'''
            logger("'''+MOD_ID+'''-注入完成");''')+'''
        }'''
    bodies=''
    END='''
    }
}
'''
    try:
        with open(f'{GAME_NAME}.cs') as f:
            lno=0
            status='defs' # 'ifs' 'bodies'
            for line in f.readlines():
                lno+=1
                g=line.split()
                if len(g[0])==0:
                    continue
                elif status=='defs':
                    if not g[0] in {'int','bool','float'}:
                        status='ifs'
                    elif g[0][0]=='[':
                        status='bodies'
                elif status=='ifs':
                    if g[0][0]=='[':
                        status='bodies'
                else:
                    if g[0] in {'int','bool','float'}:
                        status='ifs'
                if status=='defs':
                    defs.append('        public static '+g[0]+' '+g[1])
                    if len(g)>2:
                        ifs.
                elif len(g[0])==0 or g[0][0]=='#':
                    continue
                else:
                    pass

                '''
        需要：
        float amplify_factor 1f >1f desc
        float inv_amplify_factor
        生成程序的结构如下
        public static float inv_amplify_factor=1f;
            if ((amplify_factor=Config.Bind<float>("config", "amplify_factor", 16f, "产量与传送带速度乘数").Value)>1f){
                inv_amplify_factor=1/amplify_factor;
                //harmony.PatchAll(typeof(CostOrProductionValuesGetUnitsPerCycleModifier));
                harmony.PatchAll(typeof(ProductionElementGetModifierOutputSpeed));
                harmony.PatchAll(typeof(NewTransportSystemGetTickTime));
                harmony.PatchAll(typeof(MapObjectComponentProductionRemoveCosts));
                logger("Neutron3529-产量与传送带速度乘数-注入完成");
            }
        [HarmonyPatch(typeof(MobileBase.ProductionElement), "GetModifierOutputSpeed")]
        class ProductionElementGetModifierOutputSpeed {
            public static void Postfix(ref float __result) {
                __result*=amplify_factor;
            }
        }
                '''
    except FileNotFoundError:
        print(f'找不到{GAME_NAME}.cs，尝试创建一个新的{GAME_NAME}.cs')
        open(f'{GAME_NAME}.cs').close()
    with open(COMPILE_FILE,'w') as f: f.write(using+FRONT+defs+PART1+ifs+PART2+bodies+END)

generate_file(patches,args.using,args.mod_id,args.game_name,args.release)
compiles(args.extra_dll,args.mod_id,args.compile_file,args.git)
